package com.wll.aop.aspect;


import com.wll.aop.annotation.CustomNotEmpty;
import com.wll.aop.exception.ParamIsNullException;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.time.LocalDateTime;

/**
 * @author ：wanglulu
 * @date ： 2021/11/16 14:59
 * @description： 日志切面
 * @version: 1.0
 */
@Component
@Aspect
@Slf4j
public class CustomNotEmptyAspect {

    private long start;
    private long end;


    /**
     * 定义一个切入点 范围为 controller 包下的所有类
     */
    @Pointcut(value = "execution(public * com.wll.aop.controller..*.*(..))")
    public void access() {
    }


    /**
     * 前置通知 在连接点之前执行的通知
     * <p>
     * 进入切点世界  之前 处理过程
     */
    @Before("access()")
    public void doBefore() {
        System.out.println("CustomNotEmptyAspect 进入切点世界之前处理过程 >>>>>");

    }

    // 环绕增强  实在before之前就会触发
    @Around("access()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        this.start = System.currentTimeMillis();
        System.out.println("CustomNotEmptyAspect 环绕增强  实在before之前就会触发  >>>>>");
        System.out.println("aop 日志环绕开始 " + LocalDateTime.now());
        //
        MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
        // 获取拦截方法
        Method method = signature.getMethod();
        // 获取方法参数注解 返回二维数组是 因为某些参数可能存在多个注解
        Annotation[][] annotations = method.getParameterAnnotations();
        // 没有注解 直接通过
        if (annotations == null || annotations.length == 0) {
            return proceedingJoinPoint.proceed();
        }
        // 有注解
        // 获取方法参数名
        String[] parameterNames = signature.getParameterNames();
        // 获取参数值
        Object[] args = proceedingJoinPoint.getArgs();
        // 获取方法参数类型
        Class<?>[] parameterTypes = method.getParameterTypes();
        // 遍历注解
        for (int i = 0; i < annotations.length; i++) {
            for (int j = 0; j < annotations[i].length; j++) {
                // 如果该参数前面的注解是 CustomNotEmpty的实例 并且notNull() == true ， 则进行校验
                Annotation annotation = annotations[i][j];
                if (annotation instanceof CustomNotEmpty && ((CustomNotEmpty) annotation).notNull()) {
                    paramIsNull(parameterNames[i], args[i], parameterTypes[i] == null
                            ? null
                            : parameterTypes[i].getName());
                    break;
                }
            }
        }
        return proceedingJoinPoint.proceed();
    }


    //进来切点这，最后经过的一个站，也是方法正常运行结束后
    @After("access()")
    public void after(JoinPoint joinPoint) {
        this.end = System.currentTimeMillis();
        System.out.println("-aop 校验结束----" + LocalDateTime.now());
        System.out.println("-时长----" + (end - start));
    }

    /**
     * 参数非空校验，如果参数为空，则抛出ParamIsNullException异常
     *
     * @param paramName     参数key
     * @param value         参数至
     * @param parameterType 参数类型
     */
    private void paramIsNull(String paramName, Object value, String parameterType) {
        if (value == null || "".equals(value.toString().trim())) {
            System.out.println(paramName + " 为空。 " + parameterType);
            throw new ParamIsNullException(paramName, parameterType);
        }
    }

}
